/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bean.session;


import entity.CompletedGoodsEntity;
import entity.ExpectedYearOnYearGrowthEntity;
import entity.MarketSalesReportEntity;
import entity.MasterProductionScheduleMonthlyEntity;
import entity.ProductPercentageQuantityEntity;
import entity.SaleOrderReportEntity;
import entity.SalesForecastEntity;
import entity.SalesForecastToActualSalesEntity;
import entity.SalesOrderEntity;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import type.Month;
import type.SalesOrderType;

/**
 *
 * @author wei
 */
@Stateless
public class SalesForecastEntityFacade extends AbstractFacade<SalesForecastEntity> {
    @PersistenceContext(unitName = "MacTeam-warPU")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public SalesForecastEntityFacade() {
        super(SalesForecastEntity.class);
    }

    public Collection<SalesForecastEntity> createLongTerm(ExpectedYearOnYearGrowthEntity current) {
        SalesForecastEntity forecast1 = new SalesForecastEntity();
        SalesForecastEntity forecast2 = new SalesForecastEntity();
        SalesForecastEntity forecast3 = new SalesForecastEntity();
        SalesForecastEntity forecast4 = new SalesForecastEntity();
        SalesForecastEntity forecast5 = new SalesForecastEntity();
        SalesForecastEntity forecast6 = new SalesForecastEntity();
        
        ArrayList<SalesForecastEntity> list = new ArrayList<SalesForecastEntity>();
        list.add(forecast1);
        list.add(forecast2);
        list.add(forecast3);
        list.add(forecast4);
        list.add(forecast5);
        list.add(forecast6);
        
        if(current.getForecastPeriodType().getPeriodNum()==1){
            list.get(0).setMonthOfSales(Month.JANUARY);
            list.get(1).setMonthOfSales(Month.FEBRUARY);
            list.get(2).setMonthOfSales(Month.MARCH);
            list.get(3).setMonthOfSales(Month.APRIL);
            list.get(4).setMonthOfSales(Month.MAY);
            list.get(5).setMonthOfSales(Month.JUNE); 
            
          }else{
            list.get(0).setMonthOfSales(Month.JULY);
            list.get(1).setMonthOfSales(Month.AUGUST);
            list.get(2).setMonthOfSales(Month.SEPTEMBER);
            list.get(3).setMonthOfSales(Month.OCTOBER);
            list.get(4).setMonthOfSales(Month.NOVEMBER);
            list.get(5).setMonthOfSales(Month.DECEMBER);
            
        }
        
        for(SalesForecastEntity forecast:list){
                forecast.setYearOfSales(current.getYearOfSales());
                forecast.setExpectedYoYGrowth(current);
                forecast.setPreviousYearBase(calculatePreviousYearBase(forecast));
                forecast.setPreviousPromoSales(calculatePreviousPromoSales(forecast));
                forecast.setPreviousYearSales(forecast.getPreviousPromoSales()+forecast.getPreviousYearBase());
                forecast.setBaseProjection(calculateBaseProjection(forecast));
                forecast.setAdjustedBaseProjection(forecast.getBaseProjection());
                forecast.setForecast(calculateForecast(forecast));
                forecast.setHistoricalPPQ(createHistoricalPPQ(forecast));
                forecast.setClassicBarForecast(forecast.getClassicBarForecast());
                forecast.setPremiumBarForecast(forecast.getPremiumBarForecast());
//              em.persist(forecast);
            }
        
        Collection<SalesForecastEntity> total = list;
       
        return total;
        
        
        
    }


    
    public ArrayList<ProductPercentageQuantityEntity> createHistoricalPPQ(SalesForecastEntity forecast){
        ArrayList<ProductPercentageQuantityEntity> ppqList = new ArrayList<ProductPercentageQuantityEntity>();
        
        ProductPercentageQuantityEntity classicNuts = new ProductPercentageQuantityEntity();
        classicNuts.setProduct(findProductByName("Classic Nutri Bar (Nuts)"));
        classicNuts.setPercentage(calculateProductPercentage(forecast, classicNuts.getProduct()));
        classicNuts.setQuantity(calculateProductHistoricalSales(forecast,classicNuts.getProduct()));
        classicNuts.setSalesForecast(forecast);
        
        ProductPercentageQuantityEntity classicFruits = new ProductPercentageQuantityEntity();
        classicFruits.setProduct(findProductByName("Classic Nutri Bar (Fruits)"));
        classicFruits.setPercentage(calculateProductPercentage(forecast, classicFruits.getProduct()));
        classicFruits.setQuantity(calculateProductHistoricalSales(forecast,classicFruits.getProduct()));
        classicFruits.setSalesForecast(forecast);
        
        ProductPercentageQuantityEntity chocoNuts = new ProductPercentageQuantityEntity();
        chocoNuts.setProduct(findProductByName("Premium Power Bar (Chocolate Nuts)"));
        chocoNuts.setPercentage(calculateProductPercentage(forecast, chocoNuts.getProduct()));
        chocoNuts.setQuantity(calculateProductHistoricalSales(forecast,chocoNuts.getProduct()));
        chocoNuts.setSalesForecast(forecast);
        
        ProductPercentageQuantityEntity redFruits = new ProductPercentageQuantityEntity();
        redFruits.setProduct(findProductByName("Premium Power Bar (Redcurrant Fruits)"));
        redFruits.setPercentage(calculateProductPercentage(forecast, redFruits.getProduct()));
        redFruits.setQuantity(calculateProductHistoricalSales(forecast,redFruits.getProduct()));
        redFruits.setSalesForecast(forecast);
        
        ppqList.add(classicNuts);
        ppqList.add(classicFruits);
        ppqList.add(chocoNuts);
        ppqList.add(redFruits);
        
        
        return ppqList;
    }

    public long calculatePreviousYearBase(SalesForecastEntity forecast) {
        int year = forecast.getYearOfSales();
        Month month = forecast.getMonthOfSales();
        long totalQuantity = 0;
        
        Collection<SaleOrderReportEntity> reportList = findAllNormalReports(year,month);
        
        for(SaleOrderReportEntity report: reportList){
            totalQuantity+=report.getQuantity();
        }
//        System.out.println("TOtal Quantity lala is "+ totalQuantity);
        return totalQuantity;
        
    }

    public Collection<SaleOrderReportEntity> findAllNormalReports(int year, Month month) {
        year = year-1; // finding of previous year's all normal reports
        int orderNum =1;
        SalesOrderType type = SalesOrderType.fromOrderNum(orderNum);
        Query query = (Query) em.createQuery("select s from SaleOrderReport s WHERE s.yearOfSales =:year and s.monthOfSales=:month and s.type=:type ");
        query.setParameter("year", year);
        query.setParameter("month",month);
        query.setParameter("type",type);
//        System.out.println("1. the size is "+ query.getResultList().size());
        Collection<SaleOrderReportEntity> list= (Collection<SaleOrderReportEntity>)query.getResultList(); 
//        System.out.println("thse size is "+list.size());
        return list;
    }
    
     public Collection<SaleOrderReportEntity> findAllPromoReports(int year, Month month) {
        year = year-1;// finding of previous year's all promo reports
        int orderNum =2;
        SalesOrderType type = SalesOrderType.fromOrderNum(orderNum);
        Query query = (Query) em.createQuery("select s from SaleOrderReport s WHERE s.yearOfSales =:year and s.monthOfSales=:month and s.type=:type");
        query.setParameter("year", year);
        query.setParameter("month",month);
        query.setParameter("type",type);
        Collection<SaleOrderReportEntity> list= (Collection<SaleOrderReportEntity>)query.getResultList(); 
        return list;
    }

    public long calculatePreviousPromoSales(SalesForecastEntity forecast) {
        int year = forecast.getYearOfSales();
        Month month = forecast.getMonthOfSales();
        long totalQuantity = 0;
        
        Collection<SaleOrderReportEntity> reportList = findAllPromoReports(year,month);
        
        for(SaleOrderReportEntity report: reportList){
            totalQuantity+=report.getQuantity();
        }
        
        return totalQuantity;
    }

    public long calculateBaseProjection(SalesForecastEntity forecast) {
        double growth = forecast.getExpectedYoYGrowth().getGrowthRate();
        double monthlyGrowth = forecast.getMonthlyGrowthAdjustment();
                
        long previousYearBase = forecast.getPreviousYearBase();
        long baseProjection;
        
        if(growth>=0){
            
            baseProjection = (long)(previousYearBase*(100+growth)/100);
            
        }
        else{
            baseProjection = (long)(previousYearBase*(100-growth)/100);
        }
        
        if(monthlyGrowth>=0){
            baseProjection = (long)(baseProjection*(100+monthlyGrowth)/100);
        }
        else{
            baseProjection = (long)(baseProjection*(100-monthlyGrowth)/100);
        }
        
        return baseProjection;
        
    }

    public long calculateForecast(SalesForecastEntity forecast) {
        long adjustedBaseProjection = forecast.getAdjustedBaseProjection();
        long forecastValue = adjustedBaseProjection + forecast.getExpectedMonthlyPromo();
        return forecastValue;
    }

    private CompletedGoodsEntity findProductByName(String productName) {
        Query query = (Query) em.createQuery("select c from CompletedGoods c WHERE c.productName =:productName");
        query.setParameter("productName", productName);
         List<CompletedGoodsEntity> list = (List<CompletedGoodsEntity>) query.getResultList();
        return list.get(0);
        
    }

    private double calculateProductPercentage(SalesForecastEntity forecast, CompletedGoodsEntity product) {
        DecimalFormat df = new DecimalFormat("0.000");
        
        long totalQuantity = forecast.getPreviousYearSales();
//        System.out.println("totalQuantity= "+totalQuantity );
        long productQuantity = calculateProductHistoricalSales(forecast,product);
//        System.out.println("productQuantity = " +productQuantity  );
        double percentage = (Double.valueOf(Long.toString(productQuantity)).doubleValue())/(Double.valueOf(Long.toString(totalQuantity)).doubleValue());
        percentage = Math.round(percentage*1000)/1000.0;
        percentage = Double.valueOf(df.format(percentage));
//        System.out.println("percentage = "+ percentage);
        return percentage;
        
    }

    private long calculateProductHistoricalSales(SalesForecastEntity forecast, CompletedGoodsEntity product) {
        int year = forecast.getYearOfSales()-1;
        Month month = forecast.getMonthOfSales();
        List<SaleOrderReportEntity> list = getOrderReportByProduct(year,month,product);
//        System.out.println("size of list is + " + list.size());
        long quantity = 0;
        for(SaleOrderReportEntity s: list){
            quantity+= s.getQuantity();
            
        }
        return quantity;
    }

    private List<SaleOrderReportEntity> getOrderReportByProduct(int year,Month month, CompletedGoodsEntity product) {
        String productName = product.getProductName();
        
       Query query = (Query) em.createQuery("select s from SaleOrderReport s WHERE s.yearOfSales =:year and s.product.productName =:productName and s.monthOfSales =:month");
        query.setParameter("year", year);
        query.setParameter("productName", productName);
        query.setParameter("month",month);
         List<SaleOrderReportEntity> list= (List<SaleOrderReportEntity>)query.getResultList(); 
        return list;
    }

    public ArrayList<SalesForecastEntity> findShortTermSalesForecast(int year, Month month) {
       int startingYear;
       int startingMonth;
       
       int monthNum = month.getMonthNum();
       if(monthNum>3){
       startingYear = year;
       startingMonth = monthNum-3;
       }
       else{
           startingYear = year-1;
           startingMonth = 12+(monthNum-3);
       }
       
       int targetYear = startingYear;
       int targetMonth = startingMonth;
       ArrayList<SalesForecastEntity> list = new ArrayList<SalesForecastEntity>();
       for(int i = 1; i<=3; i++){
           list.add(findSalesForecast(targetYear,Month.fromMonthNum(targetMonth)));
           if(targetMonth==12){
               targetYear +=1;
               targetMonth = 1;
           }
           else{
               targetMonth +=1;
           }
       }
       return list;
       
       
         
    }

    public SalesForecastEntity findSalesForecast(int targetYear, Month month) {
//        System.out.println("finding year "+targetYear);
//        System.out.println("finding month "+month);
       Query query = (Query) em.createQuery("select s from SalesForecast s WHERE s.yearOfSales =:year and s.monthOfSales=:month ");
        query.setParameter("year", targetYear);
       
        query.setParameter("month",month);
         SalesForecastEntity report;
        try{
        report = (SalesForecastEntity) query.getSingleResult(); 
        }
        catch(NoResultException e){
        report = new SalesForecastEntity();
        report.setYearOfSales(targetYear);
        report.setMonthOfSales(month);
        report.setForecast(0);
        }
        return report;
    }

    public ArrayList<MarketSalesReportEntity> findActualTotalSales(int year, Month month) {
        int startingYear;
       int startingMonth;
       
       int monthNum = month.getMonthNum();
       if(monthNum>3){
       startingYear = year;
       startingMonth = monthNum-3;
       }
       else{
           startingYear = year-1;
           startingMonth = 12+(monthNum-3);
       }
       
       int targetYear = startingYear;
       int targetMonth = startingMonth;
       ArrayList<MarketSalesReportEntity> list = new ArrayList<MarketSalesReportEntity>();
       for(int i = 1; i<=3; i++){
           
           list.add(createActualSales(targetYear,Month.fromMonthNum(targetMonth)));
           if(targetMonth==12){
               targetYear +=1;
               targetMonth = 1;
           }
           else{
               targetMonth +=1;
           }
       }
       return list;
    }

    private MarketSalesReportEntity createActualSales(int targetYear, Month month) {
        MarketSalesReportEntity actualSale = new MarketSalesReportEntity();
        actualSale.setYear(targetYear);
        actualSale.setMonth(month);
       
        actualSale.setSalesValue(findGrossSales(targetYear,month));
//         System.out.println("actualSale.year "+actualSale.getYear());
//        System.out.println("actualSale.month "+actualSale.getMonth());
//        System.out.println("actualSale.saleValue "+ actualSale.getSalesValue());
//        if(actualSale.getSalesValue()==0){
//            actualSale.setSalesValue(500);
//        }
        return actualSale;
    }

    public long findGrossSales(int targetYear, Month month) {
        System.out.println("findGrossSales "+targetYear+" "+month);
        long grossRequirement = 0;
         ArrayList<SaleOrderReportEntity> normalReports = new ArrayList<SaleOrderReportEntity>(findAllNormalReports(targetYear+1,month));
         ArrayList<SaleOrderReportEntity> promoReports = new ArrayList<SaleOrderReportEntity>(findAllPromoReports(targetYear+1,month));
         for(SaleOrderReportEntity s: normalReports){
             grossRequirement+= s.getQuantity();
         }
         for(SaleOrderReportEntity x: promoReports){
             grossRequirement+= x.getQuantity();
         }
         return grossRequirement;
    }

    public MasterProductionScheduleMonthlyEntity findSameMonthMps(SalesForecastEntity current) {
        int year = current.getYearOfSales();
        Month month = current.getMonthOfSales();
        
        try{  
       Query query = (Query) em.createQuery("select s from MasterProductionScheduleMonthly s WHERE s.yearOfProduction =:year and s.monthOfProduction =:month and s.salesForecast IS NOT NULL");
        query.setParameter("year", year);
        
        query.setParameter("month",month);
         List<MasterProductionScheduleMonthlyEntity> list= (List<MasterProductionScheduleMonthlyEntity>)query.getResultList(); 
       
         return list.get(0);
         }catch(Exception ex){
         return null;
         }
    }

    public Object findSalesForecastManagementReport(SalesForecastToActualSalesEntity s) {
        int year = s.getYear();
        int month = s.getMonth();
        
        Query query = (Query) em.createQuery("select s from SalesForecastToActualSales s WHERE s.year=:year and s.month=:month");
        query.setParameter("year", year);
        
        query.setParameter("month",month);
        SalesForecastToActualSalesEntity result = null;
        try{
        result = (SalesForecastToActualSalesEntity)query.getSingleResult();
        }catch(NoResultException ex){
            return null;
        }
        
        return result;
    }

    public void createForecastManagementReport(SalesForecastToActualSalesEntity s) {
        em.persist(s);
    }
    
}

